<?php
/**
 * A simple description for this script
 *
 * PHP Version 5.2.4 or Upper version
 *
 * @package    Password Limitter
 * @author     Hidehito NOZAWA aka Suin <http://suin.asia/>
 * @copyright  2010 Hidehito NOZAWA
 * @license    http://www.gnu.org/licenses/gpl-2.0.html GNU GPL v2 or later
 *
 */

if ( !defined('XOOPS_ROOT_PATH') ) exit;

class PasswordLimitter extends XCube_ActionFilter
{
	function preBlockFilter()
	{
		$this->mRoot->mDelegateManager->add('User_ActionFrame.CreateAction', 'PasswordLimitterMain::checkPassword');
		$this->mRoot->mDelegateManager->add('User_ActionFrame.CreateAction', 'PasswordLimitterMain::updateExpire');
		$this->mRoot->mDelegateManager->add('Legacypage.Misc.Access', 'PasswordLimitterMain::admin');
		$this->mRoot->mDelegateManager->add('Site.CheckLogin.Success', 'PasswordLimitterMain::checkExpire', XCUBE_DELEGATE_PRIORITY_FINAL);
		$this->mRoot->mDelegateManager->add('Legacy.Event.RegistUser.Success', 'PasswordLimitterMain::newUser');
	}
}

class PasswordLimitterMain
{
	protected static $msgs = array(
		"You set password %s days ago. Please change it now for security." => "前回パスワードを設定してから%s日以上経過しました。パスワードの変更をおすすめします。",
		"Initialize" => "全ユーザのパスワード期限を設定日時に再変更する。",
		"Expire Day" => "パスワード有効期限(N日間)",
	);

	protected static $version = '1.2';

	function prepare()
	{
		if ( strtolower(_CHARSET) != 'utf-8' )
		{
			mb_convert_variables(_CHARSET, 'UTF-8', self::$msgs);
		}
	}

	function updateExpire(&$userActionFrame)
	{
		if ( $userActionFrame->mActionName == 'EditUser' ) return;

		if ( !isset($_SESSION['password_limitter_pass']) ) return;

		$newPass = $_SESSION['password_limitter_pass'];

		unset($_SESSION['password_limitter_pass']);

		$savedPass = self::_loadPass();

		if ( $newPass != $savedPass ) return;

		self::_updateExpire();
	}

	function checkPassword(&$userActionFrame)
	{
		if ( $userActionFrame->mActionName != 'EditUser' ) return;

		if ( $_SERVER['REQUEST_METHOD'] != 'POST' ) return;

		if ( !isset($_POST['pass']) or !$_POST['pass'] ) return;

		$oldPass = self::_loadPass();
		$newPass = md5($_POST['pass']);

		if ( $oldPass == $newPass ) return;

		$_SESSION['password_limitter_pass'] = $newPass;
	}

	function admin()
	{
		self::prepare();

		if ( !isset($_GET['password_limitter']) ) return;

		$root =& XCube_Root::getSingleton();
		if ( !$root->mContext->mUser->isInRole('Site.Owner') ) return;

		$method = '_page'.preg_replace('/[^A-Za-z0-9]/', '', $_GET['password_limitter']);

		if ( method_exists(__CLASS__, $method) )
		{
			self::$method();
		}

		die;
	}

	function checkExpire(&$xoopsUser)
	{
		self::prepare();

		if ( !is_object($xoopsUser) ) return;

		if ( !self::_isConfigExists() ) return;

		$expireDate = self::_loadExpire();

		if ( $expireDate == '0000-00-00' ) return;

		$expireDate  = intval(str_replace('-', '', $expireDate));
		$currentDate = intval(date('Ymd'));

		if ( $currentDate > $expireDate )
		{
			$expireDay = self::_loadConfig();
			$msg = sprintf(self::msg("You set password %s days ago. Please change it now for security."), $expireDay);
			redirect_header(XOOPS_URL.'/edituser.php', 5, $msg);
		}
	}

	function newUser(&$xoopsUser)
	{
		$db =& Database::getInstance();
		$usersTable = $db->prefix('users');
		$expireDay = self::_loadConfig();
		$expireTimeStamp = strtotime("+".$expireDay." days");
		$expireDate = date('Y-m-d', $expireTimeStamp);
		$uid = $xoopsUser->uid();
		$sql = "UPDATE `%s` SET `password_limit` = '%s' WHERE `uid` = '%s'";
		$sql = sprintf($sql, $usersTable, $expireDate, $uid);

		$result = $db->query($sql);
	}

	function _pageAdmin()
	{
		?>
<form action="misc.php?password_limitter=install" method="post">
<div style="text-align:center">
<h1>Password Limitter Installation</h1>
<input type="submit" name="install" value="INSTALL" />
</div>
</form>
<form action="misc.php?password_limitter=uninstall" method="post">
<div style="text-align:center">
<h1>Password Limitter Uninstallation</h1>
<input type="submit" name="uninstall" value="UNINSTALL" />
</div>
</form>
		<?php
	}

	function _pageInstall()
	{
		if ( self::_addField() )
		{
			$messages[] = "Adding a field `password_limit` is OK.";
		}
		else
		{
			$messages[] = "[ERROR] Adding a field `password_limit` is NG.";
		}

		if ( !self::_isConfigExists() )
		{
			if ( self::_addConfig() )
			{
				$messages[] = "Adding a configure item `passowrd_limitter_expire` is OK.";
			}
			else
			{
				$messages[] = "[ERROR] Adding a configure item `passowrd_limitter_expire` is NG.";
			}
		}

		$expireDate = date('Y-m-d', strtotime('+30 days'));

		if ( self::_initializeField($expireDate) )
		{
			$messages[] = "Field initialization OK.";
		}
		else
		{
			$messages[] = "[ERROR] Field initialization NG.";
		}

		?>
		<ul>
		<?php foreach ( $messages as $message ): ?>
		<li><?php echo $message; ?></li>
		<?php endforeach ?>
		</ul>

		<div style="text-align:center;">
		<a href="misc.php?password_limitter=config">GO TO CONFIG PAGE</a>
		</div>
		<?php
	}


	function _pageUninstall()
	{
		if ( self::_dropField() )
		{
			$messages[] = "Dropping a field `password_limit` is OK.";
		}
		else
		{
			$messages[] = "[ERROR] Dropping a field `password_limit` is NG.";
		}

		if ( self::_isConfigExists() )
		{
			if ( self::_removeConfig() )
			{
				$messages[] = "Deleting a configure item `passowrd_limitter_expire` is OK.";
			}
			else
			{
				$messages[] = "[ERROR] Deleting a configure item `passowrd_limitter_expire` is NG.";
			}
		}

		?>
		<ul>
		<?php foreach ( $messages as $message ): ?>
		<li><?php echo $message; ?></li>
		<?php endforeach ?>
		</ul>

		<div style="text-align:center;">
		<a href="index.php">GO TO HOME</a>
		</div>
		<?php
	}

	function _pageConfig()
	{
		$expireDay = self::_loadConfig();

		if ( $_SERVER['REQUEST_METHOD'] == 'POST' )
		{
			if ( isset($_POST['expire_day']) and $_POST['expire_day'] > 0 )
			{
				if ( self::_updateConfig($_POST['expire_day']) )
				{
					if ( isset($_POST['initialize']) )
					{
						$expireDay = self::_loadConfig();
						$expireDate = date('Y-m-d', strtotime('+'.$expireDay.' days'));
						self::_initializeField($expireDate);
					}

					redirect_header('misc.php?password_limitter=config', 3, "Updated.");
				}
				else
				{
					redirect_header('misc.php?password_limitter=config', 3, "Database Error.");
				}
				die;
			}
		}

		?>
<form action="misc.php?password_limitter=config" method="post">
<div style="text-align:center">
<h1>Password Limitter Configure</h1>
<h3><?php echo self::msg("Expire Day"); ?></h3>
<input type="text" name="expire_day" value="<?php echo htmlspecialchars($expireDay); ?>" size="3" maxlenght="3" /><br />
<input type="checkbox" name="initialize" value="1" /> <?php echo self::msg("Initialize"); ?><br />
<input type="submit" name="save" value="Save" />
</div>
</form>
		<?php
	}

	function _loadPass()
	{
		global $xoopsUser;

		$db =& Database::getInstance();
		$usersTable = $db->prefix('users');
		$uid = $xoopsUser->uid();
		$sql = "SELECT `pass` FROM `%s` WHERE `uid` = '%u'";
		$sql = sprintf($sql, $usersTable, $uid);

		$result = $db->query($sql);
		list($pass) = $db->fetchRow($result);

		return $pass;
	}

	function _loadExpire()
	{
		global $xoopsUser;

		$db =& Database::getInstance();
		$usersTable = $db->prefix('users');
		$uid = $xoopsUser->uid();
		$sql = "SELECT `password_limit` FROM `%s` WHERE `uid` = '%u'";
		$sql = sprintf($sql, $usersTable, $uid);

		$result = $db->query($sql);
		list($expire) = $db->fetchRow($result);

		return $expire;
	}

	function _updateExpire()
	{
		global $xoopsUser;

		$db =& Database::getInstance();
		$usersTable = $db->prefix('users');
		$expireDay = self::_loadConfig();
		$expireTimeStamp = strtotime("+".$expireDay." days");
		$expireDate = date('Y-m-d', $expireTimeStamp);
		$uid = $xoopsUser->uid();
		$sql = "UPDATE `%s` SET `password_limit` = '%s' WHERE `uid` = '%s'";
		$sql = sprintf($sql, $usersTable, $expireDate, $uid);

		$result = $db->queryF($sql);
	}

	function _isConfigExists()
	{
		$db =& Database::getInstance();
		$configTable = $db->prefix('config');

		$sql = "SELECT COUNT(*) FROM `%s` WHERE `conf_name` = 'passowrd_limitter_expire'";
		$sql = sprintf($sql, $configTable);

		$result = $db->query($sql);
		list($total) = $db->fetchRow($result);

		return ( $total > 0 );
	}

	function _addConfig()
	{
		$db =& Database::getInstance();
		$configTable = $db->prefix('config');

		$sql = "INSERT INTO `%s` SET `conf_name` = 'passowrd_limitter_expire', `conf_value` = '30', `conf_formtype` = 'textbox', `conf_valuetype` = 'int'";
		$sql = sprintf($sql, $configTable);

		return $db->query($sql);
	}

	function _removeConfig()
	{
		$db =& Database::getInstance();
		$configTable = $db->prefix('config');
		$sql = "DELETE FROM `%s` WHERE `conf_name` = 'passowrd_limitter_expire'";
		$sql = sprintf($sql, $configTable);

		return $db->query($sql);
	}

	function _loadConfig()
	{
		$db =& Database::getInstance();
		$configTable = $db->prefix('config');

		$sql = "SELECT `conf_value` FROM `%s` WHERE `conf_name` = 'passowrd_limitter_expire'";
		$sql = sprintf($sql, $configTable);

		$result = $db->query($sql);
		list($expireDay) = $db->fetchRow($result);

		return $expireDay;
	}

	function _addField()
	{
		$db =& Database::getInstance();
		$userTable = $db->prefix('users');
		$sql = "ALTER TABLE `%s` ADD `password_limit` DATE NOT NULL";
		$sql = sprintf($sql, $userTable);

		return $db->query($sql);
	}

	function _initializeField($expireDate)
	{
		$expireDate = addslashes($expireDate);
		$db =& Database::getInstance();
		$userTable = $db->prefix('users');
		$sql = "UPDATE `%s` SET `password_limit` = '%s'";
		$sql = sprintf($sql, $userTable, $expireDate);

		return $db->query($sql);
	}

	function _dropField()
	{
		$db =& Database::getInstance();
		$userTable = $db->prefix('users');
		$sql = "ALTER TABLE `%s` DROP `password_limit`";
		$sql = sprintf($sql, $userTable);

		return $db->query($sql);
	}

	function _updateConfig($expireDay)
	{
		$db =& Database::getInstance();
		$configTable = $db->prefix('config');
		$expireDay = intval($expireDay);
		$sql = "UPDATE `%s` SET `conf_value` = '%u' WHERE `conf_name` = 'passowrd_limitter_expire'";
		$sql = sprintf($sql, $configTable, $expireDay);

		return $db->query($sql);
	}

	function msg($msg)
	{
		if ( isset(self::$msgs[$msg]) )
		{
			return self::$msgs[$msg];
		}

		return $msg;
	}
}

?>